function A402()
    % logistic回归——对线性可分问题，找到一个超平面，能将两个不同的类区分开。
    format long;
    % 生成固定数量的探地雷达样本
    nSamples = 1000000;                                                      % 设定总样本数
    rng('default');                                                          % 保证随机数据可重复

    % 生成横纵坐标数据
    xCoords = (rand(nSamples, 1) * 80) - 40;                                 % 横坐标数据
    yCoords = randn(nSamples, 1) * 10;                                       % 纵坐标数据

    % -----------------------------
    % 生成分层地下结构
    % -----------------------------
    x_min = min(xCoords);
    x_max = max(xCoords);
    x_range = linspace(x_min, x_max, 1000);  
    y_boundary_base = 0.75 * sin(x_range / 5) + 0.5 * cos(x_range / 10);
    noise_curve = randn(size(x_range)) * 0.2;
    noise_curve_smooth = movmean(noise_curve, 20);
    y_boundary = y_boundary_base + noise_curve_smooth;
    curveBoundary = interp1(x_range, y_boundary, xCoords, 'spline');
    BoundarySide = double(yCoords > curveBoundary);
    Material = repmat("Rock", nSamples, 1);
    Material(BoundarySide == 1) = "Concrete";
    DielectricConstant = zeros(nSamples, 1);
    concreteIdx = (BoundarySide == 1);
    DielectricConstant(concreteIdx) = 7 + 0.5 * randn(sum(concreteIdx), 1);  
    rockIdx = (BoundarySide == 0);
    DielectricConstant(rockIdx) = 8 + 1.5 * randn(sum(rockIdx), 1);
    theta = linspace(0, 2*pi, 100)';
    r = 1.5 + rand(size(theta)) * 0.75;
    hole_x = -16 + r .* cos(theta);  
    hole_y = -6 + r .* sin(theta);
    hole_x2 = 10 + r .* cos(theta);
    hole_y2 = -8 + r .* sin(theta);
    inHole = inpolygon(xCoords, yCoords, hole_x, hole_y) | inpolygon(xCoords, yCoords, hole_x2, hole_y2);
    voidIndices = find(inHole & rockIdx); 
    DielectricConstant(voidIndices) = 1;
    Material(voidIndices) = "Air";
    noise_y = randn(nSamples, 1) * 20;
    NoisyY = yCoords + noise_y;
    
    % -----------------------------
    % 构造数据集
    % -----------------------------
    data = table(NoisyY, DielectricConstant, BoundarySide, Material, ...
                 'VariableNames', {'YCoords', 'DielectricConstant', 'BoundarySide', 'Material'});
    disp('生成的探地雷达数据集前几行：');
    disp(head(data));

    % -----------------------------
    % **划分训练集与测试集**
    % -----------------------------
    rng('default');                                                          % 保证随机划分一致
    cv = cvpartition(nSamples, 'HoldOut', 0.2);                              % 80% 训练集，20% 测试集
    TrainData = data(training(cv), :);
    TestData = data(test(cv), :);
    
    % 保存数据集
    save('TrainData.mat', 'TrainData');
    save('TestData.mat', 'TestData');

    % -----------------------------
    % 可视化地下结构分界线
    % -----------------------------
    [sortedX, sortIdx] = sort(xCoords);
    sortedBoundary = curveBoundary(sortIdx);
    figure;
    hold on;
    plot(sortedX, sortedBoundary, 'k-', 'LineWidth', 1, 'DisplayName', 'Boundary Line');
    scatter(xCoords, yCoords, 10, DielectricConstant, 'filled');
    xlabel('xCoords');
    ylabel('yCoords');
    title('地下结构分界线与数据点');
    colorbar;
    grid on;
    hold off;
    
    % -----------------------------
    % 逻辑回归模型训练与评估
    % -----------------------------
    disp('正在训练逻辑回归模型...');
    mdl = fitglm(TrainData, 'BoundarySide ~ YCoords + DielectricConstant', ...
                 'Distribution', 'binomial', 'Link', 'logit');
    disp('逻辑回归模型训练完成。');
    disp(mdl);
    
    % -----------------------------
    % 预测
    % -----------------------------
    predictedProbs = predict(mdl, TestData);
    trueLabels = TestData.BoundarySide;
    [Xroc, Yroc, ~, AUROC] = perfcurve(trueLabels, predictedProbs, 1);
    figure;
    plot(Xroc, Yroc, 'b-', 'LineWidth', 2);
    xlabel('False Positive Rate');
    ylabel('True Positive Rate');
    title(['ROC 曲线 (AUROC = ', num2str(AUROC, '%.5f'), ')']);
    grid on;
end